home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / sml_nj / 93src.lha / src / boot / math.sml < prev    next >
Encoding:
Text File  |  1993-01-27  |  9.0 KB  |  292 lines

  1. (* Copyright 1989 by AT&T Bell Laboratories *)
  2. (* The following functions were adapted from the 4.3BSD math library.
  3.    Eventually, each machine supported should have a hand-coded math
  4.    functor with more efficient versions of these functions.
  5.  
  6. ***************************************************************************
  7. *                                                                         * 
  8. * Copyright (c) 1985 Regents of the University of California.             *
  9. *                                                                         * 
  10. * Use and reproduction of this software are granted  in  accordance  with *
  11. * the terms and conditions specified in  the  Berkeley  Software  License *
  12. * Agreement (in particular, this entails acknowledgement of the programs' *
  13. * source, and inclusion of this notice) with the additional understanding *
  14. * that  all  recipients  should regard themselves as participants  in  an *
  15. * ongoing  research  project and hence should  feel  obligated  to report *
  16. * their  experiences (good or bad) with these elementary function  codes, *
  17. * using "sendbug 4bsd-bugs@BERKELEY", to the authors.                     *
  18. *                                                                         *
  19. * K.C. Ng, with Z-S. Alex Liu, S. McDonald, P. Tang, W. Kahan.            *
  20. * Revised on 5/10/85, 5/13/85, 6/14/85, 8/20/85, 8/27/85, 9/11/85.        *
  21. *                                                                         *
  22. ***************************************************************************
  23.  
  24. *)
  25.  
  26. signature MATH =    (* must be alphabetical order *)
  27.   sig
  28.     exception Ln and Sqrt
  29.     val arctan : real -> real
  30.     val cos : real -> real
  31.     val exp : real -> real
  32.     val ln : real -> real
  33.     val sin : real -> real
  34.     val sqrt : real -> real
  35.   end
  36.  
  37. structure Math : MATH = struct
  38.  
  39. structure Assembly : ASSEMBLY = Core.Assembly
  40.  
  41. infix 7 * /
  42. infix 6 + -
  43. infix 4 > < >= <=
  44.  
  45. exception Sqrt
  46. exception Ln
  47. exception Overflow = Assembly.Overflow
  48.  
  49. val op + : real * real -> real = InLine.fadd
  50. val op - : real * real -> real = InLine.fsub
  51. val op * : real * real -> real = InLine.fmul
  52. val op / : real * real -> real = InLine.fdiv
  53. val op > : real * real -> bool = InLine.fgt
  54. val op < : real * real -> bool = InLine.flt
  55. val op >= : real * real -> bool = InLine.fge
  56. val op <= : real * real -> bool = InLine.fle
  57.  
  58. val ieql : int * int -> bool = InLine.ieql
  59. val ineq : int * int -> bool = InLine.ineq
  60. val feql : real * real -> bool = InLine.feql
  61. val lessu : int * int -> bool = InLine.lessu
  62.  
  63. (* This function is IEEE double-precision specific *)
  64. fun scalb(x,k) = if lessu(InLine.+(k,1022),2046) then Assembly.A.scalb(x,k)
  65.                  else let val k1 = InLine.div(k,2)
  66.                   val k2 = InLine.-(k,k1)
  67.                in scalb(scalb(x,k1),k2)
  68.               end
  69.  
  70. val two_to_the_54 = 18014398509481984.0
  71.  
  72. (* This function is IEEE double-precision specific *)
  73. fun logb(x) = 
  74.     case Assembly.A.logb x
  75.      of ~1023 => (* denormalized number *)
  76.              InLine.-(Assembly.A.logb(x*two_to_the_54),54)
  77.       | i => i
  78.  
  79. val negone = ~1.0
  80. val zero = 0.0
  81. val half = 0.5
  82. val one = 1.0
  83. val two = 2.0
  84. val four = 4.0
  85.  
  86. val ~ : real -> real = fn x => InLine.fsub(zero,x)
  87.  
  88. fun copysign(a,b) =
  89.       case (a<zero,b<zero) of
  90.           (true,true) => a
  91.         | (false,false) => a
  92.         | _ => ~a
  93.  
  94. fun abs x = if x < zero then ~x else x
  95. fun op mod(a,b) = InLine.-(a,InLine.*(InLine.div(a,b),b))
  96.  
  97. val floor = Assembly.A.floor
  98. fun truncate n = if n < 0.0 then InLine.~(floor(~n)) else floor n
  99. fun ceiling n = InLine.~(floor(~n))
  100.  
  101. local fun loop 0 = zero
  102.         | loop n = let val x = two * loop(InLine.rshift(n,1))
  103.            in case InLine.andb(n,1) of 0 => x | 1 => x + one
  104.            end
  105. in fun real n = if InLine.<(n,0) then ~(loop(InLine.~ n)) else loop n
  106. end
  107.  
  108. val maxint = 4503599627370496.0 (* This is the IEEE double-precision
  109.                    maxint; won't work accurately on VAX *)
  110.  
  111. fun realround x = if x>=0.0 then x+maxint-maxint else x-maxint+maxint
  112. (* realround(x) returns x rounded to some nearby integer, almost always
  113.    the nearest integer. *)
  114.  
  115. (* sin/cos *)
  116. local
  117.     val S0 = ~1.6666666666666463126E~1
  118.     val S1 =  8.3333333332992771264E~3
  119.     val S2 = ~1.9841269816180999116E~4
  120.     val S3 =  2.7557309793219876880E~6
  121.     val S4 = ~2.5050225177523807003E~8
  122.     val S5 =  1.5868926979889205164E~10
  123. in  fun sin__S z = (z*(S0+z*(S1+z*(S2+z*(S3+z*(S4+z*S5))))))
  124. end
  125.  
  126. local
  127.     val C0 =  4.1666666666666504759E~2
  128.     val C1 = ~1.3888888888865301516E~3
  129.     val C2 =  2.4801587269650015769E~5
  130.     val C3 = ~2.7557304623183959811E~7
  131.     val C4 =  2.0873958177697780076E~9
  132.     val C5 = ~1.1250289076471311557E~11
  133. in  fun cos__C z = (z*z*(C0+z*(C1+z*(C2+z*(C3+z*(C4+z*C5))))))
  134. end
  135.  
  136. val PIo4   =  7.8539816339744827900E~1
  137. val PIo2   =  1.5707963267948965580E0
  138. val PI3o4  =  2.3561944901923448370E0
  139. val PI     =  3.1415926535897931160E0
  140. val PI2    =  6.2831853071795862320E0
  141. val oneOver2Pi = 0.15915494309189533576888376337251486
  142.  
  143. local
  144.     val thresh =  2.6117239648121182150E~1
  145. in  fun S y = y + y * sin__S(y*y)
  146.     fun C y =
  147.     let val yy = y*y
  148.         val c = cos__C yy
  149.         val Y = yy/two
  150.     in  if Y < thresh then one - (Y - c)
  151.         else half - (Y - half - c)
  152.     end
  153. end
  154.     fun sin x =
  155.     let val xover2pi = x * oneOver2Pi
  156.         val x = PI2*(xover2pi - realround(xover2pi))
  157.            (* now, probably,  ~pi <= x <= pi, except on vaxes *)
  158.         fun lessPIo2 x = if x>PIo4 then C(PIo2-x) else S x
  159.         fun lessPI x = if x>PIo2 then lessPIo2(PI-x) else lessPIo2 x
  160.         fun positive x = if x>PI then sin(x-PI2) (* exceedingly rare *)
  161.                          else lessPI x
  162.      in if x>=0.0 
  163.         then positive x
  164.             else ~(positive(~x))
  165.     end
  166.  
  167.     fun cos x = sin(PIo2-x)
  168.  
  169. local
  170.     val p1 =  1.3887401997267371720E~2
  171.     val p2 =  3.3044019718331897649E~5
  172.     val q1 =  1.1110813732786649355E~1
  173.     val q2 =  9.9176615021572857300E~4
  174. in  fun exp__E(x:real,c:real) =
  175.     let val z = x*x
  176.         val p = z*(p1+z*p2)
  177.         val q = z*(q1+z*q2)
  178.         val xp= x*p 
  179.         val xh= x*half
  180.         val w = xh-(q-xp)
  181.         val c = c+x*((xh*w-(q-(p+p+xp)))/(one-w)+c)
  182.     in  z*half+c
  183.     end
  184. end
  185.  
  186. (* for exp and ln *)
  187. val ln2hi = 6.9314718036912381649E~1
  188. val ln2lo = 1.9082149292705877000E~10
  189. val sqrt2 = 1.4142135623730951455E0
  190. val lnhuge =  7.1602103751842355450E2
  191. val lntiny = ~7.5137154372698068983E2
  192. val invln2 =  1.4426950408889633870E0
  193.  
  194. fun exp(x:real) =
  195.     let fun exp_norm x =
  196.         let (* argument reduction : x --> x - k*ln2 *)
  197.         val k = floor(invln2*x+copysign(half,x)) (* k=NINT(x/ln2) *)
  198.         val K = real k
  199.         (* express x-k*ln2 as z+c *)
  200.         val hi = x-K*ln2hi
  201.         val lo = K*ln2lo
  202.         val z = hi - lo
  203.         val c = (hi-z)-lo
  204.         (* return 2^k*[expm1(x) + 1] *)
  205.         val z = z + exp__E(z,c)
  206.         in  scalb(z+one,k)
  207.         end
  208.     in    if x <= lnhuge 
  209.          then if x >= lntiny
  210.             then exp_norm x
  211.             else zero
  212.          else raise Overflow
  213.     end
  214.  
  215. local
  216.     val L1 = 6.6666666666667340202E~1
  217.     val L2 = 3.9999999999416702146E~1
  218.     val L3 = 2.8571428742008753154E~1
  219.     val L4 = 2.2222198607186277597E~1
  220.     val L5 = 1.8183562745289935658E~1
  221.     val L6 = 1.5314087275331442206E~1
  222.     val L7 = 1.4795612545334174692E~1
  223. in  fun log__L(z) = z*(L1+z*(L2+z*(L3+z*(L4+z*(L5+z*(L6+z*L7))))))
  224. end
  225.  
  226. fun ln(x:real) =
  227.       if x <= zero then raise Ln
  228.     else let val k = logb(x)
  229.          val x = scalb(x,InLine.~ k)
  230.          val (x,k) = if ieql(k,~1022) (* subnormal no. *)
  231.              then let val n = logb(x)
  232.                   in  (scalb(x,InLine.~ n),InLine.+(k,n)) end
  233.              else (x,k)
  234.          val (k,x) = if x >= sqrt2 then (InLine.+(k,1),x*half) 
  235.                        else (k,x)
  236.          val K = real k
  237.          val x = x - one
  238.          (* compute log(1+x) *)
  239.          val s = x/(two+x)
  240.          val t = x*x*half
  241.          val z = K*ln2lo+s*(t+log__L(s*s))
  242.          val x = x + (z - t)
  243.          in  K*ln2hi+x 
  244.         end
  245.  
  246. local
  247.     val athfhi =  4.6364760900080611433E~1
  248.     val athflo =  1.0147340032515978826E~18
  249.     val at1hi =   0.78539816339744830676
  250.     val at1lo =   1.11258708870781088040E~18
  251.     val a1     =  3.3333333333333942106E~1
  252.     val a2     = ~1.9999999999979536924E~1
  253.     val a3     =  1.4285714278004377209E~1
  254.     val a4     = ~1.1111110579344973814E~1
  255.     val a5     =  9.0908906105474668324E~2
  256.     val a6     = ~7.6919217767468239799E~2
  257.     val a7     =  6.6614695906082474486E~2
  258.     val a8     = ~5.8358371008508623523E~2
  259.     val a9     =  4.9850617156082015213E~2
  260.     val a10    = ~3.6700606902093604877E~2
  261.     val a11    =  1.6438029044759730479E~2
  262.  
  263.     fun atn(t,hi,lo) = (* for ~0.4375 <= t <= 0.4375 *)
  264.            let val z = t*t
  265.             in hi+(t+(lo-t*(z*(a1+z*(a2+z*(a3+z*(a4+z*(a5+z*(a6+z*(a7+
  266.                 z*(a8+z*(a9+z*(a10+z*a11)))))))))))))
  267.            end
  268.  
  269.     fun atan(t) = (* 0 <= t <= 1 *)
  270.         if t <= 0.4375 then atn(t,zero,zero)
  271.      else if t <= 0.6875 then atn((t-half)/(one+half*t), athfhi, athflo)
  272.      else atn((t-one)/(one+t), at1hi,at1lo)
  273.  
  274.     fun atanpy y = (* y>=0 *)
  275.     if y>one then PIo2 - atan(one/y) else atan(y)
  276.  
  277. in  fun arctan y = if y<=0.0 then ~(atanpy(~y)) else atanpy y
  278. end
  279.  
  280. fun sqrt(x: real) =
  281.       if x<=zero then if x<zero then raise Sqrt else x
  282.       else 
  283.         let val k = 6 (* log base 2 of the precision *)
  284.         val n = InLine.rshift(logb(x),1)
  285.         val x = scalb(x, InLine.~(InLine.lshift(n,1)))
  286.         fun iter(0,g) = g
  287.               | iter(i,g) = iter(InLine.-(i,1), half * (g + x/g))
  288.          in scalb(iter(k,one),n)
  289.         end
  290.  
  291. end
  292.